<?php
declare (strict_types = 1);

namespace app\controller;

use app\middleware\Auth;
use think\facade\Filesystem;
use think\facade\Request;
use think\exception\ValidateException;

/**
 * 文件上传控制器
 * @OA\Tag(name="文件上传", description="文件上传接口")
 */
class UploadController extends ApiBaseController
{
    /**
     * 前置中间件
     * @var array
     */
    protected $middleware = [
        Auth::class
    ];
    
    /**
     * 上传文件
     *
     * @OA\Post(
     *     path="/api/upload/file",
     *     summary="通用文件上传",
     *     description="上传文件到服务器，返回访问URL",
     *     tags={"文件上传"},
     *     security={{"bearerAuth":{}}},
     *     @OA\RequestBody(
     *         required=true,
     *         @OA\MediaType(
     *             mediaType="multipart/form-data",
     *             @OA\Schema(
     *                 required={"file"},
     *                 @OA\Property(property="file", type="string", format="binary", description="要上传的文件"),
     *                 @OA\Property(property="type", type="string", enum={"image", "video", "audio", "document"}, example="image", description="文件类型：image-图片，video-视频，audio-音频，document-文档"),
     *                 @OA\Property(property="dir", type="string", example="qrcode", description="保存目录，默认为type值对应的目录")
     *             )
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="上传成功",
     *         @OA\JsonContent(
     *             @OA\Property(property="code", type="integer", example=200),
     *             @OA\Property(property="msg", type="string", example="上传成功"),
     *             @OA\Property(property="data", type="object",
     *                 @OA\Property(property="url", type="string", example="https://example.com/storage/qrcode/202504211234567.jpg", description="文件访问URL"),
     *                 @OA\Property(property="path", type="string", example="qrcode/202504211234567.jpg", description="文件相对路径"),
     *                 @OA\Property(property="name", type="string", example="avatar.jpg", description="原始文件名"),
     *                 @OA\Property(property="size", type="integer", example=123456, description="文件大小(字节)"),
     *                 @OA\Property(property="mime", type="string", example="image/jpeg", description="文件MIME类型")
     *             )
     *         )
     *     ),
     *     @OA\Response(
     *         response=400,
     *         description="上传失败",
     *         @OA\JsonContent(
     *             @OA\Property(property="code", type="integer", example=400),
     *             @OA\Property(property="msg", type="string", example="文件类型不允许"),
     *             @OA\Property(property="data", type="object")
     *         )
     *     ),
     *     @OA\Response(
     *         response=401,
     *         description="未授权",
     *         @OA\JsonContent(
     *             @OA\Property(property="code", type="integer", example=401),
     *             @OA\Property(property="msg", type="string", example="请先登录"),
     *             @OA\Property(property="data", type="object")
     *         )
     *     )
     * )
     *
     * @return \think\Response
     */
    public function file()
    {
        // 校验登录
        $check = $this->checkLogin();
        if ($check !== true) return $check;
        
        try {
            \think\facade\Log::info('开始处理文件上传请求');
            
            // 获取文件
            $file = Request::file('file');
            if (!$file) {
                return $this->error('请选择要上传的文件');
            }
            
            // 获取文件类型参数
            $type = Request::param('type', 'image');
            $saveDir = Request::param('dir', $type);
            
            // 验证文件
            $validateRules = $this->getValidateRules($type);
            try {
                validate($validateRules)->check(['file' => $file]);
            } catch (ValidateException $e) {
                return $this->error($e->getMessage());
            }
            
            // 上传到public/storage目录下
            $saveName = Filesystem::disk('public')->putFile($saveDir, $file);
            
            if (!$saveName) {
                return $this->error('文件上传失败');
            }
            
            // 获取文件信息
            $fileInfo = [
                'url' => request()->domain() . '/storage/' . $saveName,
                'path' => $saveName,
                'name' => $file->getOriginalName(),
                'size' => $file->getSize(),
                'mime' => $file->getMime(),
            ];
            
            \think\facade\Log::info('文件上传成功: ' . json_encode($fileInfo, JSON_UNESCAPED_UNICODE));
            
            return $this->success($fileInfo, '上传成功');
            
        } catch (\Exception $e) {
            \think\facade\Log::error('文件上传异常: ' . $e->getMessage() . ' | 跟踪: ' . $e->getTraceAsString());
            return $this->error('文件上传失败: ' . $e->getMessage());
        }
    }
    
    /**
     * 获取不同类型文件的验证规则
     *
     * @param string $type 文件类型
     * @return array 验证规则
     */
    protected function getValidateRules($type)
    {
        $rules = [
            'file' => [],
        ];
        
        switch ($type) {
            case 'image':
                $rules['file'] = [
                    'fileSize' => 10 * 1024 * 1024, // 10MB
                    'fileExt' => 'jpg,jpeg,png,gif,webp,bmp',
                    'fileMime' => 'image/jpeg,image/png,image/gif,image/webp,image/bmp',
                ];
                break;
                
            case 'video':
                $rules['file'] = [
                    'fileSize' => 100 * 1024 * 1024, // 100MB
                    'fileExt' => 'mp4,avi,mov,wmv,flv,mkv',
                    'fileMime' => 'video/mp4,video/avi,video/quicktime,video/x-ms-wmv,video/x-flv,video/x-matroska',
                ];
                break;
                
            case 'audio':
                $rules['file'] = [
                    'fileSize' => 20 * 1024 * 1024, // 20MB
                    'fileExt' => 'mp3,wav,ogg,flac,aac',
                    'fileMime' => 'audio/mpeg,audio/wav,audio/ogg,audio/flac,audio/aac',
                ];
                break;
                
            case 'document':
                $rules['file'] = [
                    'fileSize' => 20 * 1024 * 1024, // 20MB
                    'fileExt' => 'doc,docx,xls,xlsx,ppt,pptx,pdf,txt',
                    'fileMime' => 'application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/pdf,text/plain',
                ];
                break;
                
            default:
                $rules['file'] = [
                    'fileSize' => 10 * 1024 * 1024, // 10MB
                    'fileExt' => 'jpg,jpeg,png,gif,mp4,mp3,pdf,doc,docx,xls,xlsx',
                ];
                break;
        }
        
        return $rules;
    }
} 